//
// Created by yangw on 2018-2-28.
//

#include "WlCallJava.h"

WlCallJava::WlCallJava(_JavaVM *javaVM, JNIEnv *env, jobject *obj) {

    this->javaVM = javaVM;
    this->jniEnv = env;
    this->jobj = *obj;
    this->jobj = env->NewGlobalRef(jobj);

    jclass jlz = jniEnv->GetObjectClass(jobj);
    if (!jlz) {
        if (LOG_DEBUG) {
            LOGE("get jclass wrong");
        }
        return;
    }

    jmid_parpared = env->GetMethodID(jlz, "onCallParpared", "()V");
    jmid_load = env->GetMethodID(jlz, "onCallLoad", "(Z)V");
    jmid_timeinfo = env->GetMethodID(jlz, "onCallTimeInfo", "(II)V");
    jmid_error = env->GetMethodID(jlz, "onCallError", "(ILjava/lang/String;)V");
    jmid_complete = env->GetMethodID(jlz, "onCallComplete", "()V");
    jmid_render = env->GetMethodID(jlz, "onCallRenderYuv", "(II[B[B[B)V");
    jmid_support = env->GetMethodID(jlz, "onCallSupportCodec",
                                    "(Ljava/lang/String;)Z");// 当有方法找不到会全部报错
    jmid_initMediaCodec = env->GetMethodID(jlz, "onCallInitMediacodec",
                                           "(Ljava/lang/String;II[B[B)V");// 当有方法找不到会全部报错
    jmid_decodePacket = env->GetMethodID(jlz, "onCallDecode", "(I[B)V");// 当有方法找不到会全部报错


}

void WlCallJava::onCallParpared(int type) {

    if (type == MAIN_THREAD) {
        jniEnv->CallVoidMethod(jobj, jmid_parpared);
    } else if (type == CHILD_THREAD) {
        JNIEnv *jniEnv;
        if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
            if (LOG_DEBUG) {
                LOGE("get child thread jnienv worng");
            }
            return;
        }
        jniEnv->CallVoidMethod(jobj, jmid_parpared);
        javaVM->DetachCurrentThread();
    }

}

void WlCallJava::onCallLoad(int type, bool load) {

    if (type == MAIN_THREAD) {
        jniEnv->CallVoidMethod(jobj, jmid_load, load);
    } else if (type == CHILD_THREAD) {
        JNIEnv *jniEnv;
        if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
            if (LOG_DEBUG) {
                LOGE("call onCallLoad worng");
            }
            return;
        }
        jniEnv->CallVoidMethod(jobj, jmid_load, load);
        javaVM->DetachCurrentThread();
    }


}

void WlCallJava::onCallTimeInfo(int type, int curr, int total) {
    if (type == MAIN_THREAD) {
        jniEnv->CallVoidMethod(jobj, jmid_timeinfo, curr, total);
    } else if (type == CHILD_THREAD) {
        JNIEnv *jniEnv;
        if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
            if (LOG_DEBUG) {
                LOGE("call onCallTimeInfo worng");
            }
            return;
        }
        jniEnv->CallVoidMethod(jobj, jmid_timeinfo, curr, total);
        javaVM->DetachCurrentThread();
    }
}

WlCallJava::~WlCallJava() {

}

void WlCallJava::onCallError(int type, int code, char *msg) {
    if (type == MAIN_THREAD) {
        jstring jmsg = jniEnv->NewStringUTF(msg);
        jniEnv->CallVoidMethod(jobj, jmid_error, code, jmsg);
        jniEnv->DeleteLocalRef(jmsg);
    } else if (type == CHILD_THREAD) {
        JNIEnv *jniEnv;
        if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
            if (LOG_DEBUG) {
                LOGE("call onCallError worng");
            }
            return;
        }
        jstring jmsg = jniEnv->NewStringUTF(msg);
        jniEnv->CallVoidMethod(jobj, jmid_error, code, jmsg);
        jniEnv->DeleteLocalRef(jmsg);
        javaVM->DetachCurrentThread();
    }
}

void WlCallJava::onCallComplete(int type) {
    if (type == MAIN_THREAD) {
        jniEnv->CallVoidMethod(jobj, jmid_complete);
    } else if (type == CHILD_THREAD) {
        JNIEnv *jniEnv;
        if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
            if (LOG_DEBUG) {
                LOGE("call onCallComplete worng");
            }
            return;
        }
        jniEnv->CallVoidMethod(jobj, jmid_complete);
        javaVM->DetachCurrentThread();
    }
}

void
WlCallJava::onCallRender(int type, int wdith, int height, uint8_t *fy, uint8_t *fu, uint8_t *fv) {

    JNIEnv *jniEnv;
    if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
        if (LOG_DEBUG) {
            LOGE("call onCallComplete worng");
        }
        return;
    }
    jbyteArray byte_Y = jniEnv->NewByteArray(wdith * height);
    jniEnv->SetByteArrayRegion(byte_Y, 0, wdith * height, reinterpret_cast<const jbyte *>(fy));


    jbyteArray byte_U = jniEnv->NewByteArray(wdith * height / 4);
    jniEnv->SetByteArrayRegion(byte_U, 0, wdith * height / 4, reinterpret_cast<const jbyte *>(fu));

    jbyteArray byte_V = jniEnv->NewByteArray(wdith * height / 4);
    jniEnv->SetByteArrayRegion(byte_V, 0, wdith * height / 4, reinterpret_cast<const jbyte *>(fv));

    jniEnv->CallVoidMethod(jobj, jmid_render, wdith, height, byte_Y, byte_U, byte_V);

    jniEnv->DeleteLocalRef(byte_Y);
    jniEnv->DeleteLocalRef(byte_U);
    jniEnv->DeleteLocalRef(byte_V);

    javaVM->DetachCurrentThread();


}

bool WlCallJava::onCallSupportCodec(const char *ffcodecname) {

    JNIEnv *jniEnv;
    bool issupport = false;
    if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
        if (LOG_DEBUG) {
            LOGE("call onCallComplete worng");
        }
        return issupport;
    }
    jstring codec_name = jniEnv->NewStringUTF(ffcodecname);
    issupport = jniEnv->CallBooleanMethod(jobj, jmid_support, codec_name);

    jniEnv->DeleteLocalRef(codec_name);
    javaVM->DetachCurrentThread();

    return issupport;
}

void
WlCallJava::onCallInitMediaCodec(const char *mime, int wdith, int height, int csd_0_size,
                                 int csd_1_size, uint8_t *csd_0,
                                 uint8_t *csd_1) {

    JNIEnv *jniEnv;
    if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
        if (LOG_DEBUG) {
            LOGE("call onCallComplete worng");
        }
        return;
    }
    jstring codec_name = jniEnv->NewStringUTF(mime);
    jbyteArray pArray = jniEnv->NewByteArray(csd_0_size);
    jniEnv->SetByteArrayRegion(pArray, 0, csd_0_size, reinterpret_cast<const jbyte *>(csd_0));
    jbyteArray pArray1 = jniEnv->NewByteArray(csd_1_size);
    jniEnv->SetByteArrayRegion(pArray1, 0, csd_1_size, reinterpret_cast<const jbyte *>(csd_1));
    jniEnv->CallVoidMethod(jobj, jmid_initMediaCodec, codec_name, wdith, height, pArray, pArray1);

    jniEnv->DeleteLocalRef(codec_name);
    jniEnv->DeleteLocalRef(pArray);
    jniEnv->DeleteLocalRef(pArray1);
    javaVM->DetachCurrentThread();
}

void WlCallJava::onCallDecodeAvPacket(int size, uint8_t *data) {
    JNIEnv *jniEnv;
    if (javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK) {
        if (LOG_DEBUG) {
            LOGE("call onCallComplete worng");
        }
        return;
    }
    jbyteArray pArray = jniEnv->NewByteArray(size);
    jniEnv->SetByteArrayRegion(pArray, 0, size, reinterpret_cast<const jbyte *>(data));
    jniEnv->CallVoidMethod(jobj, jmid_decodePacket, size, pArray);

    jniEnv->DeleteLocalRef(pArray);
    javaVM->DetachCurrentThread();
}
